'''
A class that translates GTP commands to the model classes methods.
'''
from pygo1963.model.Board import Board
from pygo1963.model.Move import Move
from pygo1963.model.Vertex import Vertex
from pygo1963.model import Constants

class GTPEngine():
    
    DEFAULT_BOARD_SIZE = 9
    MSG_UNKNOWN_COMMAND = 'unknown command'
    MSG_SINTAX_ERROR = 'sintax error'
    MSG_WRONG_SIZE = 'unacceptable size'
    MSG_ILLEGAL_MOVE = 'illegal move'
    MSG_CANNOT_UNDO = 'cannot undo'
    MSG_INVALID_COLOR = 'invalid color'
    
    def __init__(self, player):
        
        self.player = player
        self.board = Board(self.DEFAULT_BOARD_SIZE)
        self.received_quit = False
    
    def process_command(self, command):
        """ 
        Takes a GTP command string, processes it, and returns the GTP response.
        The command is assumed to be preprocessed.
        """
        cmd_id, command_name, args = self.split_command(command)
        
        if not hasattr(self, 'gtp_' + command_name):
            return self.failure_response(cmd_id, self.MSG_UNKNOWN_COMMAND)
        
        return getattr(self, 'gtp_' + command_name)(cmd_id, args)    
    
    def split_command(self, command):        
        """
        Splits a command string in its id (if present), the command name,
        and a list of arguments.         
        """
        cmd_id, command_name, args = '', '', []
        
        word_list = command.split()
        
        if word_list:
            
            if len(word_list) > 1 and word_list[0].isdigit():
                cmd_id = word_list.pop(0)
            
            command_name = word_list.pop(0)
            args = word_list
        
        return cmd_id, command_name, args
    
    def failure_response(self, cmd_id, error_message):
        """ Return a GTP formatted failure response. """
        return "?%s %s\n\n" % (cmd_id, error_message)
    
    def success_response(self, cmd_id, response=''):
        """ Return a GTP formatted success response. """
        if response != '':
            return "=%s %s\n\n" % (cmd_id, response)
        
        return "=%s\n\n" % cmd_id
    
    #PROTOCOL COMMANDS
    def gtp_protocol_version(self, cmd_id, args):
        return self.success_response(cmd_id, '2')
    
    def gtp_name(self, cmd_id, args):
        return self.success_response(cmd_id, 'pygo1963')
    
    def gtp_known_command(self, cmd_id, args):

        cmd_name = args[0] if args else ''
        known = 'false'
        
        if hasattr(self, 'gtp_' + cmd_name):
            known = 'true'
        
        return self.success_response(cmd_id, known)
    
    def gtp_list_commands(self, cmd_id, args):
        
        cmd_list = [cmd.replace('gtp_', '') for cmd in dir(self) 
                                            if cmd.startswith('gtp_')]
        
        cmd_list = '\n'.join(cmd_list)
        
        return self.success_response(cmd_id, cmd_list)
    
    def gtp_quit(self, cmd_id, args):
        
        self.received_quit = True
        
        return self.success_response(cmd_id)
    
    def gtp_boardsize(self, cmd_id, args):
        
        if not args or not args[0].isdigit():
            return self.failure_response(cmd_id, self.MSG_SINTAX_ERROR)
        
        size = int(args[0])
        if size < 2 or size > 25:
            return self.failure_response(cmd_id, self.MSG_WRONG_SIZE)
        
        self.board = Board(size)
        
        return self.success_response(cmd_id)        
    
    def gtp_clear_board(self, cmd_id, args):
        
        self.board = Board(self.board.size)
        
        return self.success_response(cmd_id)
    
    def gtp_play(self, cmd_id, args):
        
        if len(args) < 2:
            return self.failure_response(cmd_id, self.MSG_SINTAX_ERROR)
        
        try:
            vertex = Vertex.from_string(args[1])
            move = Move(args[0], vertex)        
        except:
            return self.failure_response(cmd_id, self.MSG_SINTAX_ERROR)
        
        try:
            self.board.make_move(move)            
        except:
            return self.failure_response(cmd_id, self.MSG_ILLEGAL_MOVE)
        
        return self.success_response(cmd_id)
    
    def gtp_genmove(self, cmd_id, args):
        #The color is ignored        
        
        move = None
        while not move:
            
            move = self.player.make_move(self.board.copy())            
            try:
                self.board.make_move(move)            
            except:
                self.player.notify_invalid_move()
                move = None        
        
        return self.success_response(cmd_id, move.vertex)
    
    def gtp_undo(self, cmd_id, args):
        
        try:
            self.board.undo_move()
        except:
            return self.failure_response(cmd_id, self.MSG_CANNOT_UNDO)
        
        return self.success_response(cmd_id)
    
    def gtp_showboard(self, cmd_id, args):
        return self.success_response(cmd_id, self.board)
    
    
    #PRIVATE EXTENSIONS
    #supported by gnugo
    def gtp_captures(self, cmd_id, args):
        """        
        Returns the amount of captures of the specified color. An Atari Go 
        board is assumed, so the color will have at most one capture, and in 
        that case it would win the game.        
        """
        
        color = args[0].lower() if args else ''
        
        if color == 'w' or color == 'white':
            color = Constants.WHITE_COLOR            
        elif color == 'b' or color == 'black':
            color = Constants.BLACK_COLOR
        else:
            return self.failure_response(cmd_id, self.MSG_INVALID_COLOR)
        
        captures = 0
        if self.board.winner == color:
            captures = 1
        
        return self.success_response(cmd_id, captures)
    
        